home *** CD-ROM | disk | FTP | other *** search
/ Just Call Me Internet / Just Call Me Internet.iso / prog / atari / c / nos042_s / arp.c < prev    next >
C/C++ Source or Header  |  1994-09-16  |  9KB  |  311 lines

  1. /* Address Resolution Protocol (ARP) functions. Sits between IP and
  2.  * Level 2, mapping IP to Level 2 addresses for all outgoing datagrams.
  3.  * Copyright 1991 Phil Karn, KA9Q
  4.  */
  5.  
  6. /****************************************************************************
  7. *    $Id: arp.c 1.2 93/07/16 11:41:45 ROOT_DOS Exp $
  8. *    14 Jun 93    1.2        GT    Fix warnings.                                    *
  9. *
  10. *  ATARI Version by David Nash - dnash@chaos.demon.co.uk
  11. *
  12. *  ANSI style function definitions
  13. *
  14. ****************************************************************************/
  15.  
  16. #include "global.h"
  17. #include "mbuf.h"
  18. #include "timer.h"
  19. #include "iface.h"
  20. #include "enet.h"
  21. #include "ax25.h"
  22. #include "icmp.h"
  23. #include "ip.h"
  24. #include "arp.h"
  25. #include "icmp.h"
  26.  
  27. static void arp_output __ARGS((struct iface *iface,int16 hardware,int32 target));
  28.  
  29. /* Hash table headers */
  30. struct arp_tab *Arp_tab[HASHMOD];
  31.  
  32. struct arp_stat Arp_stat;
  33.  
  34. /* Resolve an IP address to a hardware address; if not found,
  35.  * initiate query and return NULLCHAR.  If an address is returned, the
  36.  * interface driver may send the packet; if NULLCHAR is returned,
  37.  * res_arp() will have saved the packet on its pending queue,
  38.  * so no further action (like freeing the packet) is necessary.
  39.  */
  40. char *res_arp(
  41.     struct iface *iface,        /* Pointer to interface block */
  42.     int16 hardware,            /* Hardware type */
  43.     int32 target,                /* Target IP address */
  44.     struct mbuf *bp)            /* IP datagram to be queued if unresolved */
  45. {
  46.     register struct arp_tab *arp;
  47.     struct ip ip;
  48.  
  49.     if((arp = arp_lookup(hardware,target)) != NULLARP && arp->state == ARP_VALID)
  50.         return arp->hw_addr;
  51.     if(arp != NULLARP){
  52.         /* Earlier packets are already pending, kick this one back
  53.          * as a source quench
  54.          */
  55.         ntohip(&ip,&bp);
  56.         icmp_output(&ip,bp,ICMP_QUENCH,0,NULL);
  57.         free_p(bp);
  58.     } else {
  59.         /* Create an entry and put the datagram on the
  60.          * queue pending an answer
  61.          */
  62.         arp = arp_add(target,hardware,NULLCHAR,0);
  63.         enqueue(&arp->pending,bp);
  64.         arp_output(iface,hardware,target);
  65.     }
  66.     return NULLCHAR;
  67. }
  68. /* Handle incoming ARP packets. This is almost a direct implementation of
  69.  * the algorithm on page 5 of RFC 826, except for:
  70.  * 1. Outgoing datagrams to unresolved addresses are kept on a queue
  71.  *    pending a reply to our ARP request.
  72.  * 2. The names of the fields in the ARP packet were made more mnemonic.
  73.  * 3. Requests for IP addresses listed in our table as "published" are
  74.  *    responded to, even if the address is not our own.
  75.  */
  76. void
  77. arp_input(iface,bp)
  78. struct iface *iface;
  79. struct mbuf *bp;
  80. {
  81.     struct arp arp;
  82.     struct arp_tab *ap;
  83.     struct arp_type *at;
  84.     int i;
  85.     
  86.     Arp_stat.recv++;
  87.     if(ntoharp(&arp,&bp) == -1)    /* Convert into host format */
  88.         return;
  89.     if(arp.hardware >= NHWTYPES){
  90.         /* Unknown hardware type, ignore */
  91.         Arp_stat.badtype++;
  92.         return;
  93.     }
  94.     at = &Arp_type[arp.hardware];
  95.     if(arp.protocol != at->iptype){
  96.         /* Unsupported protocol type, ignore */
  97.         Arp_stat.badtype++;
  98.         return;
  99.     }
  100.     if(/*uchar(arp.hwalen) > MAXHWALEN ||*/ uchar(arp.pralen) != sizeof(int32)){
  101.         /* Incorrect protocol addr length (different hw addr lengths
  102.          * are OK since AX.25 addresses can be of variable length)
  103.          */
  104.         Arp_stat.badlen++;
  105.         return;
  106.     }
  107.     if(memcmp(arp.shwaddr,at->bdcst,at->hwalen) == 0){
  108.         /* This guy is trying to say he's got the broadcast address! */
  109.         Arp_stat.badaddr++;
  110.         return;
  111.     }
  112.     /* If this guy is already in the table, update its entry
  113.      * unless it's a manual entry (noted by the lack of a timer)
  114.      */
  115.     ap = NULLARP;    /* ap plays the role of merge_flag in the spec */
  116.     if((ap = arp_lookup(arp.hardware,arp.sprotaddr)) != NULLARP
  117.      && dur_timer(&ap->timer) != 0){
  118.         ap = arp_add(arp.sprotaddr,arp.hardware,arp.shwaddr,0);
  119.     }
  120.     /* See if we're the address they're looking for */
  121.     if(ismyaddr(arp.tprotaddr) != NULLIF){
  122.         if(ap == NULLARP)    /* Only if not already in the table */
  123.             arp_add(arp.sprotaddr,arp.hardware,arp.shwaddr,0);
  124.  
  125.         if(arp.opcode == ARP_REQUEST){
  126.             /* Swap sender's and target's (us) hardware and protocol
  127.              * fields, and send the packet back as a reply
  128.              */
  129.             memcpy(arp.thwaddr,arp.shwaddr,(int16)uchar(arp.hwalen));
  130.             /* Mark the end of the sender's AX.25 address
  131.              * in case he didn't
  132.              */
  133.             if(arp.hardware == ARP_AX25)
  134.                 arp.thwaddr[uchar(arp.hwalen)-1] |= E;
  135.  
  136.             memcpy(arp.shwaddr,iface->hwaddr,at->hwalen);
  137.             arp.tprotaddr = arp.sprotaddr;
  138.             arp.sprotaddr = iface->addr;
  139.             arp.opcode = ARP_REPLY;
  140.             if((bp = htonarp(&arp)) == NULLBUF)
  141.                 return;
  142.  
  143.             if(iface->forw != NULLIF)
  144.                 (*iface->forw->output)(iface->forw,
  145.                  arp.thwaddr,iface->forw->hwaddr,at->arptype,bp);
  146.             else 
  147.                 (*iface->output)(iface,arp.thwaddr,
  148.                  iface->hwaddr,at->arptype,bp);
  149.             Arp_stat.inreq++;
  150.         } else {
  151.             Arp_stat.replies++;
  152.         }
  153.     } else if(arp.opcode == ARP_REQUEST
  154.      && (ap = arp_lookup(arp.hardware,arp.tprotaddr)) != NULLARP
  155.      && ap->pub){
  156.         /* Otherwise, respond if the guy he's looking for is
  157.          * published in our table.
  158.          */
  159.         memcpy(arp.thwaddr,arp.shwaddr,(int16)uchar(arp.hwalen));
  160.         memcpy(arp.shwaddr,ap->hw_addr,at->hwalen);
  161.         arp.tprotaddr = arp.sprotaddr;
  162.         arp.sprotaddr = ap->ip_addr;
  163.         arp.opcode = ARP_REPLY;
  164.         if((bp = htonarp(&arp)) == NULLBUF)
  165.             return;
  166.         if(iface->forw != NULLIF)
  167.             (*iface->forw->output)(iface->forw,
  168.              arp.thwaddr,iface->forw->hwaddr,at->arptype,bp);
  169.         else 
  170.             (*iface->output)(iface,arp.thwaddr,
  171.              iface->hwaddr,at->arptype,bp);
  172.         Arp_stat.inreq++;
  173.     } else if(arp.opcode == REVARP_REQUEST){
  174.         for(i=0;i<HASHMOD;i++)
  175.             for(ap = Arp_tab[i];ap != NULLARP;ap = ap->next)
  176.                 if(memcmp(ap->hw_addr,arp.thwaddr,at->hwalen) == 0)
  177.                     goto found;
  178.     found:    if(ap != NULLARP && ap->pub){
  179.             memcpy(arp.shwaddr,iface->hwaddr,at->hwalen);
  180.             arp.tprotaddr = ap->ip_addr;
  181.             arp.sprotaddr = iface->addr;
  182.             arp.opcode = REVARP_REPLY;
  183.             if((bp = htonarp(&arp)) == NULLBUF)
  184.                 return;
  185.             if(iface->forw != NULLIF)
  186.                 (*iface->forw->output)(iface->forw,
  187.                  arp.thwaddr,iface->forw->hwaddr,REVARP_TYPE,bp);
  188.             else 
  189.                 (*iface->output)(iface,arp.thwaddr,
  190.                  iface->hwaddr,REVARP_TYPE,bp);
  191.             Arp_stat.inreq++;
  192.         }
  193.     }
  194. }
  195. /* Add an IP-addr / hardware-addr pair to the ARP table */
  196. struct arp_tab *arp_add(
  197.     int32 ipaddr,                /* IP address, host order */
  198.     int16 hardware,            /* Hardware type */
  199.     char *hw_addr,                /* Hardware address, if known; NULLCHAR otherwise */
  200.     int pub)                        /* Publish this entry? */
  201. {
  202.     struct mbuf *bp;
  203.     register struct arp_tab *ap;
  204.     struct arp_type *at;
  205.     unsigned hashval;
  206.  
  207.     if(hardware >=NHWTYPES)
  208.         return NULLARP;    /* Invalid hardware type */
  209.     at = &Arp_type[hardware];
  210.  
  211.     if((ap = arp_lookup(hardware,ipaddr)) == NULLARP){
  212.         /* New entry */
  213.         ap = (struct arp_tab *)callocw(1,sizeof(struct arp_tab));
  214.         ap->hw_addr = mallocw(at->hwalen);
  215.         ap->timer.func = arp_drop;
  216.         ap->timer.arg = ap;
  217.         ap->hardware = hardware;
  218.         ap->ip_addr = ipaddr;
  219.  
  220.         /* Put on head of hash chain */
  221.         hashval = hash_ip(ipaddr);
  222.         ap->prev = NULLARP;
  223.         ap->next = Arp_tab[hashval];
  224.         Arp_tab[hashval] = ap;
  225.         if(ap->next != NULLARP){
  226.             ap->next->prev = ap;
  227.         }
  228.     }
  229.     if(hw_addr == NULLCHAR){
  230.         /* Await response */
  231.         ap->state = ARP_PENDING;
  232.         set_timer(&ap->timer,Arp_type[hardware].pendtime * 1000L);
  233.     } else {
  234.         /* Response has come in, update entry and run through queue */
  235.         ap->state = ARP_VALID;
  236.         set_timer(&ap->timer,ARPLIFE*1000L);
  237.         memcpy(ap->hw_addr,hw_addr,at->hwalen);
  238.         ap->pub = pub;
  239.         while((bp = dequeue(&ap->pending)) != NULLBUF)
  240.             ip_route(NULLIF,bp,0);
  241.     }
  242.     start_timer(&ap->timer);
  243.     return ap;
  244. }
  245.  
  246. /* Remove an entry from the ARP table */
  247. void
  248. arp_drop(p)
  249. void *p;
  250. {
  251.     register struct arp_tab *ap;
  252.  
  253.     ap = (struct arp_tab *)p;
  254.     if(ap == NULLARP)
  255.         return;
  256.     stop_timer(&ap->timer);    /* Shouldn't be necessary */
  257.     if(ap->next != NULLARP)
  258.         ap->next->prev = ap->prev;
  259.     if(ap->prev != NULLARP)
  260.         ap->prev->next = ap->next;
  261.     else
  262.         Arp_tab[hash_ip(ap->ip_addr)] = ap->next;
  263.     free_q(&ap->pending);
  264.     free(ap->hw_addr);
  265.     free((char *)ap);
  266. }
  267.  
  268. /* Look up the given IP address in the ARP table */
  269. struct arp_tab * arp_lookup(
  270.     int16 hardware,
  271.     int32 ipaddr)
  272. {
  273.     register struct arp_tab *ap;
  274.  
  275.     for(ap = Arp_tab[hash_ip(ipaddr)]; ap != NULLARP; ap = ap->next){
  276.         if(ap->ip_addr == ipaddr && ap->hardware == hardware)
  277.             break;
  278.     }
  279.     return ap;
  280. }
  281. /* Send an ARP request to resolve IP address target_ip */
  282. static void arp_output(
  283.     struct iface *iface,
  284.     int16 hardware,
  285.     int32 target)
  286. {
  287.     struct arp arp;
  288.     struct mbuf *bp;
  289.     struct arp_type *at;
  290.  
  291.     at = &Arp_type[hardware];
  292.     if(iface->output == NULLFP)
  293.         return;
  294.     
  295.     arp.hardware = hardware;
  296.     arp.protocol = at->iptype;
  297.     arp.hwalen = at->hwalen;
  298.     arp.pralen = sizeof(int32);
  299.     arp.opcode = ARP_REQUEST;
  300.     memcpy(arp.shwaddr,iface->hwaddr,at->hwalen);
  301.     arp.sprotaddr = iface->addr;
  302.     memset(arp.thwaddr,0,at->hwalen);
  303.     arp.tprotaddr = target;
  304.     if((bp = htonarp(&arp)) == NULLBUF)
  305.         return;
  306.     (*iface->output)(iface,at->bdcst,
  307.         iface->hwaddr,at->arptype,bp);
  308.     Arp_stat.outreq++;
  309. }
  310.  
  311.